/**********************************************************
 * MODULE:    mysql
 * AUTHOR(S): Radim Blazek (radim.blazek@gmail.com)
 * PURPOSE:   MySQL database driver
 * COPYRIGHT: (C) 2001 by the GRASS Development Team
 *            This program is free software under the 
 *            GNU General Public License (>=v2). 
 *            Read the file COPYING that comes with GRASS
 *            for details.
 **********************************************************/
#include <stdlib.h>
#include <string.h>

#include <grass/gis.h>
#include <grass/dbmi.h>
#include <grass/glocale.h>

#include "globals.h"
#include "proto.h" 

int
db__driver_fetch(dbCursor *cn, int position, int *more)
{
    cursor     *c;
    dbToken    token;    
    dbTable    *table;
    int        i;

    /* get cursor token */
    token = db_get_cursor_token(cn);

    /* get the cursor by its token */
    if (!(c = (cursor *) db_find_token(token))) {
	append_error ( _("Cursor not found") );
	report_error();
	return DB_FAILED;
    }

    /* fetch on position */
    switch (position)
    { 
	case DB_NEXT:
	    c->row = mysql_fetch_row(c->res);
	    break;
	    
	case DB_CURRENT:
	    break;
	    
	case DB_PREVIOUS:
	case DB_FIRST:
	case DB_LAST:
	default:
	    append_error ( _("Cursor position is not supported "
			     "by MySQL driver") );
	    report_error();
	    return DB_FAILED;
    }

    G_debug ( 3, "row = %d nrows = %d", c->row, c->nrows );
    if ( c->row == NULL ) 
    {
	*more = 0;
	return DB_OK;
    }

    *more = 1;

    /* get the data out of the descriptor into the table */
    table = db_get_cursor_table(cn);

    for (i = 0; i < c->ncols; i++) 
    {
	int col, sqltype, mysqltype;
	dbColumn   *column;
	dbValue    *value;
	char *val;

	col = c->cols[i]; /* known column */
 		
	column = db_get_table_column (table, i);
	mysqltype  = db_get_column_host_type(column);
	sqltype = db_get_column_sqltype(column);

	value  = db_get_column_value (column);
	db_zero_string (&value->s);
	value->t.year = 0;
	value->t.month = 0;
	value->t.day = 0;
	value->t.hour = 0;
	value->t.minute = 0;
	value->t.seconds = 0.0;
	
	val = c->row[i];
	if ( !val ) {
	    value->isNull = 1;
	    continue;
	} else {
	    value->isNull = 0;
	}

	G_debug (3, "col %d, mysqltype %d, sqltype %d, val = '%s'", 
		    col, mysqltype, sqltype, c->row[col] );

	/* defined in /usr/include/mysql/mysql_com.h */	
	switch (mysqltype) 
	{
	    int ns;

	    case MYSQL_TYPE_TINY:
	    case MYSQL_TYPE_SHORT:
	    case MYSQL_TYPE_LONG:
	    case MYSQL_TYPE_INT24:
	    case MYSQL_TYPE_LONGLONG:
            case MYSQL_TYPE_YEAR:
	    	value->i = atoi ( val );
		break;

	    case MYSQL_TYPE_FLOAT:
	    case MYSQL_TYPE_DOUBLE:
	    	value->d = atof ( val );
		break;

	    /* MySQL TIMESTAMP < 4.1: YYYYMMDDHHMMSS TIMESTAMP(14)
	     *                        YYMMDDHHMMSS   TIMESTAMP(12)
	     *                        YYMMDDHHMM     TIMESTAMP(10)
	     *                        YYYYMMDD       TIMESTAMP(8)
	     *                        YYMMDD         TIMESTAMP(6)
	     *                        YYMM           TIMESTAMP(4)
	     * 			      YY             YY
	     * MySQL TIMESTAMP >= 4.1: 'YYYY-MM-DD HH:MM:SS' (19 chars) */
	    case MYSQL_TYPE_TIMESTAMP:
	    {
		char valbuf[25], buf[10];
	        memset ( valbuf, 0, 25 );	
		strcpy ( valbuf, val );

		switch ( strlen(val) ) 
		{
		    case 2: 
		    case 4: 
		    case 6: 
		    case 10: 
		    case 12: 
		        strncpy ( buf, val, 2 ); buf[2] = 0;
			value->t.year = atoi ( buf );
		        strncpy ( buf, val+2, 2 ); buf[2] = 0;
			value->t.month = atoi ( buf );
		        strncpy ( buf, val+4, 2 ); buf[2] = 0;
			value->t.day = atoi ( buf );
		        strncpy ( buf, val+6, 2 ); buf[2] = 0;
			value->t.hour = atoi ( buf );
		        strncpy ( buf, val+8, 2 ); buf[2] = 0;
			value->t.minute = atoi ( buf );
		        strncpy ( buf, val+10, 2 ); buf[2] = 0;
			value->t.seconds = atof ( buf );
			break;

		    case 8:
		    case 14:
		        strncpy ( buf, val, 4 ); buf[4] = 0;
			value->t.year = atoi ( buf );
		        strncpy ( buf, val+4, 2 ); buf[2] = 0;
			value->t.month = atoi ( buf );
		        strncpy ( buf, val+6, 2 ); buf[2] = 0;
			value->t.day = atoi ( buf );
		        strncpy ( buf, val+8, 2 ); buf[2] = 0;
			value->t.hour = atoi ( buf );
		        strncpy ( buf, val+10, 2 ); buf[2] = 0;
			value->t.minute = atoi ( buf );
		        strncpy ( buf, val+12, 2 ); buf[2] = 0;
			value->t.seconds = atof ( buf );
			break;

		    case 19:
		        ns = sscanf( val, "%4d-%2d-%2d %2d:%2d:%lf",
			     &(value->t.year), &(value->t.month), 
			     &(value->t.day), &(value->t.hour), 
			     &(value->t.minute), &(value->t.seconds) );

			if ( ns != 6 ) {
			    append_error ( _("Cannot scan timestamp: ") );
			    append_error ( val );
			    report_error();
			    return DB_FAILED;
			}
			break;

		    default:
			append_error ( _("Unknown timestamp format: ") );
			append_error ( val );
			report_error();
			return DB_FAILED;
		}
	    }
		break;

	    /* MySQL DATE: 'YYYY-MM-DD' */
	    case MYSQL_TYPE_DATE:
		ns = sscanf( val, "%4d-%2d-%2d", &(value->t.year), 
			     &(value->t.month), &(value->t.day) ); 

		if ( ns != 3 ) {
		    append_error ( _("Cannot scan date: ") );
		    append_error ( val );
		    report_error();
		    return DB_FAILED;
		}
		break;
			
	    /* MySQL DATETIME: 'HH:MM:SS' */
	    case MYSQL_TYPE_TIME:
		ns = sscanf( val, "%2d:%2d:%lf", &(value->t.hour), 
			     &(value->t.minute), &(value->t.seconds) );

		if ( ns != 3 ) {
		    append_error ( _("Cannot scan time: ") );
		    append_error ( val );
		    report_error();
		    return DB_FAILED;
		}
		break;

	    /* MySQL DATETIME: 'YYYY-MM-DD HH:MM:SS' */
	    case MYSQL_TYPE_DATETIME:
		ns = sscanf( val, "%4d-%2d-%2d %2d:%2d:%lf",
			     &(value->t.year), &(value->t.month), 
			     &(value->t.day), &(value->t.hour), 
			     &(value->t.minute), &(value->t.seconds) );

		if ( ns != 6 ) {
		    append_error ( _("Cannot scan datetime: ") );
		    append_error ( val );
		    report_error();
		    return DB_FAILED;
		}
		break;

	    case MYSQL_TYPE_STRING:
	    case MYSQL_TYPE_VAR_STRING:
	    case MYSQL_TYPE_SET:
	    case MYSQL_TYPE_ENUM:
	    case MYSQL_TYPE_BLOB:
		db_set_string ( &(value->s),  val );
		break;
	}
    }
    G_debug (3, "Row fetched" );
    return DB_OK;
}

int
db__driver_get_num_rows (cn )
            dbCursor *cn;
{
    cursor     *c;
    dbToken    token;

    /* get cursor token */
    token = db_get_cursor_token(cn);

    /* get the cursor by its token */
    if (!(c = (cursor *) db_find_token(token))) {
       append_error("Cursor not found");
       report_error();
       return DB_FAILED;
    }

    return ( c->nrows );
}

